class BaseSpec
	def to_spec
		self
	end
end

class AlwaysTrueSpec < BaseSpec
	attr_reader :attribute, :value
	
	def is_satisfied_by(thing)
		true
	end		
end

class LesserThanSpec < BaseSpec
	attr_reader :attribute, :value
		
	def initialize(attribute_being_compared, value)
		@attribute = attribute_being_compared
		@value = value
	end
	
	def is_satisfied_by(thing)
		thing[@attribute] < @value
	end
end

class GreaterThanSpec < BaseSpec
	attr_reader :attribute, :value
			
	def initialize(attribute_being_compared, value)
		@attribute = attribute_being_compared
		@value = value
	end
	
	def is_satisfied_by(thing)
		thing[@attribute] > @value
	end	
end

class EqualsSpec < BaseSpec
	attr_reader :attribute, :value
	
	def initialize(attribute_being_compared, value)
		@attribute = attribute_being_compared
		@value = value
	end
	
	def is_satisfied_by(thing)
			thing[@attribute] == @value
	end	
end


class CombinedSpec < BaseSpec
	
	def initialize
		@specs = []
	end
	
	#adds a spec to this cobined structure
	def <<(spec)
		@specs << spec
	end
	
	def first
		@specs.first
	end
	
	def second
		@specs[1]
	end
	
	
	def is_satisfied_by(thing)
		@specs.each{|spec|
			if not spec.is_satisfied_by thing
				return false
			end
		}
		
	end	
		
end

def create_spec(&spec_definition_block)
	HashQL::create_spec &spec_definition_block
end

#the array class must be able to return a composed spec from its specs
class Array
	def to_spec
		composed_spec = CombinedSpec.new
		self.each{|element| composed_spec << element}
		composed_spec
	end

	def find_elements_that(what)
		result =[]
		behavior = what.keys.first
		spec = what.values.first
		
		if behavior == :matches then
			result = result | self.select { |element| spec.is_satisfied_by element}
		end
		
		result
	end
end

module HashQL
	def HashQL.create_spec
		#this is a terrible hack. must find a decent way of doing that...
		add_hashql_methods_to_Symbol	
		result= yield
		remove_hashql_methods_from_Symbol
		result.to_spec
	end
		
	def HashQL.add_hashql_methods_to_Symbol
		#the method that performs the magic
		Symbol.send(:define_method, :create_spec_from_operator){|operator, value|
			if operator == :==
				EqualsSpec.new self, value
			elsif  operator == :>
				GreaterThanSpec.new self, value
			elsif  operator == :<
				LesserThanSpec.new self, value
			end
		}
		
		#missing methods may be operators
		Symbol.send(:define_method, :method_missing){|sym, arg|
			create_spec_from_operator sym, arg
		}
		
		#the :== must detect when the parameter is not a Symbol and call the spec builder method
		Symbol.send(:alias_method , :original_equals_operator, :== )
		Symbol.send(:define_method, :==){|other_thing|
			if (not other_thing.kind_of? Symbol)
				create_spec_from_operator :==, other_thing
			else
				original_equals_operator other_thing
			end
		}
	end
	
	def HashQL.remove_hashql_methods_from_Symbol
		#put :== back
		Symbol.send(:alias_method , :== ,:original_equals_operator)
	end
end